/**
 * *******************************************
 * user: zmq
 * describe:    connector服的逻辑处理
 * created:
 * date: 2021/8/20
 * *******************************************
 */

import {FrontendSession, pinus} from "pinus";
import RouteUtil from "../util/routeUtil";
import {logger} from "../util/logger";
import {Application} from "pinus/lib/application";
import UserDao from "../dao/mysqlDao/userDao";
import {MessagePack} from "../util/messagePack";
import {ERRORCODE} from "../util/errorCode";

/**
 * 单例模式，内存唯一指向
 */
class ConnectorService {

    private static _instance: ConnectorService = undefined;      // 声明一个 ConnectorService 对象

    /**
     * 构造函数
     */
    private constructor() {

    };

    /**
     * 返回一个唯一实例
     * @returns {ConnectorService}
     */
    public static getInstance(): ConnectorService {
        if (this._instance === undefined) {
            this._instance = new ConnectorService();
        }
        return this._instance;
    };

    /**
     * 初始化connector逻辑实例
     */
    public init(){

        return;
    }

    /**
     * 创建角色 接口
     * @param {Application} app
     * @param {FrontendSession} session
     * @param {any} msg
     * @returns {Promise<void>}
     */
    public async createRole(app: Application, session: FrontendSession, msg: any) {

        let self = this;

        let account = msg.account;
        if (!account || (typeof account) !== "string") {          // 无效账号
            return MessagePack.failResult(ERRORCODE.CONNECTOR_ACCOUNT_IS_ERROR);
        }

        let areaServerID = session.get('areaServerID');           // 从玩家session去获取绑定的areaServerID
        if (!areaServerID) {                                      // 没有areaServerID属性 则去路由分配
            RouteUtil.area(session, msg, app, (err, serverID) => {
                if (err) { // 路由异常抛出
                    return MessagePack.failResult(ERRORCODE.ROUTE_ERROR);
                }
                areaServerID = serverID;
            });
        }

        // rpc到area服，通知玩家已经执行了创建角色操作 并返回对应所需信息
        let createRoleData = await pinus.app.rpc.area.areaRemote.createRole(session, msg);
        if(createRoleData.code !== 0){       // 成功创建，则设置session信息
            // 更新session信息
            session.set('areaServerID', areaServerID);
            session.pushAll(undefined);
        }

        // 返回创建数据
        return createRoleData;
    }

    /**
     * 角色登录接口
     * @param {Application} app
     * @param {FrontendSession} session
     * @param {any} msg
     * @returns {Promise<{userInfo: any}>}
     */
    public async login(app: Application, session: FrontendSession, msg: any) {

        let uid = msg.uid;      // 客户端传递的uid   账号登录后，会把玩家账号下面的角色信息下发，客户端根据此来登录对应角色
        let sessionID = session.id;

        let clientAddress = app.get('sessionService').getClientAddressBySessionId(sessionID);
        let IP = clientAddress.ip.split('::ffff:')[1];


        let areaServerID = session.get('areaServerID');  // 从玩家session去获取绑定的areaServerID
        if (!areaServerID) {                             // 没有areaServerID属性 则去路由分配
            RouteUtil.area(session, msg, app, (err, serverID) => {
                if (err) {      // 路由异常抛出
                    return MessagePack.failResult(ERRORCODE.ROUTE_ERROR);
                }
                areaServerID = serverID;
            });
        }

        let sessionService = app.get("sessionService");            // 获取sessionService  主要作用是管理session
        if (!!sessionService.getByUid("" + uid)) {            // !!的作用是强制转换为布尔类型  结果只能是true 或者 false 不为undefined
            pinus.app.get('sessionService').kick("" + uid);    // 将玩家踢出，重新绑定
        }

        // 根据uid去获取user表 角色基本信息
        let [getUserErr, userInfo] = await UserDao.getUsersByUid(uid);
        if (getUserErr) {
            logger.info("getUserErr --> ", getUserErr);
            return MessagePack.failResult(ERRORCODE.MYSQL_GET_ERROR);
        }

        // rpc到area服，通知玩家已经执行了登录操作 并返回对应所需信息
        let loginInfo = await pinus.app.rpc.area.areaRemote.login(session, {userInfo: userInfo[0],IP:IP});
        if(loginInfo.code !== 0){     // 有错误码返回
            return loginInfo;
        }


        let extInfo = {};  // 监听close事件，当session为close状态，调用自身onUserLeave()方法
        session.on('closed', this.onUserLeave.bind(app, session, extInfo));
        session.bind("" + uid, undefined);                // session与该用户id建立一个映射关系
        session.set('areaServerID', areaServerID);                  // 设置areaServerID
        session.push('areaServerID', function (err) {     // session同步，在改变session之后需要同步，以后的请求处理中就可以获取最新session
            if (err) {
                logger.info("为session设置areaServerID失败 ---> ", err);
            }
        });


        return loginInfo;
    }


    /**
     * 玩家掉线处理
     * @param {Application} app
     * @param {FrontendSession} session
     * @param extInfo
     */
    public onUserLeave(app: Application, session: FrontendSession, extInfo: any) {

        // let self = this;
        // let uid = session.uid;
        // let areaServerID = session.get('areaServerID');

        /*********      rpc到各个服务器， 通知玩家下线   **********/

    }

}

// 抛出接口
export default ConnectorService.getInstance();